package com.foton.bpc.all.remoting.netty;

import com.foton.bpc.all.remoting.Client;
import com.foton.bpc.all.remoting.netty.adpect.HandlerAdpect;
import com.foton.bpc.all.remoting.netty.channel.BpcChannel;
import com.foton.bpc.all.remoting.netty.channel.impl.NettyChannel;
import com.foton.bpc.all.remoting.netty.codec.Codec;
import com.foton.bpc.all.remoting.netty.codec.impl.BpcCodec;
import com.foton.bpc.all.remoting.netty.handler.NettyCodecHandler;
import com.foton.bpc.all.remoting.netty.handler.NettyLogicHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.net.URI;

/**
 * @Author RenPu
 * @Date 2023/6/13 9:58
 * @Version 1.0
 * @Description: Netty客户端（服务消费端）
 **/

@Slf4j
public class NettyClient implements Client {

    BpcChannel bpcChannel=null;
    EventLoopGroup group=null;


    /**
     * 连接方法
     * @param uri
     * @param codec
     * @param handlerAdpect
     */
    @Override
    public void connect(URI uri, Codec codec, HandlerAdpect handlerAdpect) {
        try {
        //创建netty客户端
        group=new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        //绑定事件循环组
        bootstrap.group(group)
        //设置channel通道
       .channel(NioSocketChannel.class)
        //设置处理器例如：编解码器，业务处理器
       .handler(new ChannelInitializer<SocketChannel>() {
           @Override
           protected void initChannel(SocketChannel ch) throws Exception {
               ch.pipeline()
                       .addLast(new NettyCodecHandler(codec.creteInstance()))
                       .addLast(new NettyLogicHandler(handlerAdpect));
           }
       });
        //根据ip,暴露端口进行链接 同步
        ChannelFuture channelFuture = bootstrap.connect(uri.getHost(), uri.getPort()).sync();
        //获取channel赋值给bpcChannel
        bpcChannel=new NettyChannel(channelFuture.channel());
        //添加钩子函数，遇到kill -pid 程序的操作，进行优雅停机（释放资源）
         Runtime.getRuntime().addShutdownHook(new Thread(()->{
           log.info("Netty Server wants stop server !!!!!!");
           synchronized (NettyServer.class){
               try {
                   group.shutdownGracefully().sync();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
         }));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }





    /**
     * 获取chanel方法
     * @return
     */
    @Override
    public BpcChannel getBpcChanel() {
        return this.bpcChannel;
    }
}
